package org.zuel.boot.demo.service.impl;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zuel.boot.demo.Dao.DemoPermMapper;
import org.zuel.boot.demo.Dao.DemoRolePermMapper;
import org.zuel.boot.demo.Dao.DemoUserRoleMapper;
import org.zuel.boot.demo.model.*;
import org.zuel.boot.demo.param.BatchAuthParam;
import org.zuel.boot.demo.service.CommonRefService;
import org.zuel.boot.demo.service.IAuthService;
import org.zuel.boot.demo.util.ArgumentUtil;
import org.zuel.boot.demo.util.ResponseUtil;
import vo.RolePermVo;

import java.time.LocalDateTime;
import java.util.*;
@Service
public class AuthService implements IAuthService {


    private final DemoUserRoleMapper userRoleMapper;

    private final DemoRolePermMapper rolePermMapper;

    private final DemoPermMapper permMapper;//我们想看权限名字，所以引入权限mapper

    private final CommonRefService refService;

    @Autowired
    public AuthService(DemoUserRoleMapper userRoleMapper,
                       DemoRolePermMapper rolePermMapper,
                       DemoPermMapper permMapper,
                       CommonRefService refService) {
        this.userRoleMapper = userRoleMapper;
        this.rolePermMapper = rolePermMapper;
        this.permMapper = permMapper;
        this.refService = refService;
    }

    @Override
    public Object userRoleList(Integer userId, Integer roleId) {
        List<DemoUserRole> models = queryUserRole(userId, roleId);
        return ResponseUtil.ok(models);
    }

    /**
     * 查询用户-角色授权信息
     */
    private List<DemoUserRole> queryUserRole(Integer userId, Integer roleId) {
        DemoUserRoleExample example = new DemoUserRoleExample();
        DemoUserRoleExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo((byte) 0);
        if(userId != null) {
            criteria.andUserIdEqualTo(userId);
        }
        if(roleId != null) {
            criteria.andRoleIdEqualTo(roleId);
        }
        return userRoleMapper.selectByExample(example);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)//给用户授予角色
    public Object batchAuthRole(BatchAuthParam param) {
        if(!ArgumentUtil.notNull(param, param.getAuthId())) {
            return ResponseUtil.badArgument();
        }
        // 添加新角色
        if(param.getAddItems() != null && !param.getAddItems().isEmpty()) {//!= null：表示集合对象本身不是 null，即 param.getAddItems() 返回了一个有效的集合对象。size() > 0：表示集合中至少有一个元素。
            // 先获得用户已被授权角色id
            Set<Integer> authSet = existUserRoleSet(param.getAuthId());
            param.getAddItems().forEach(item -> {
                // 没有被授权的角色才写入角色信息，避免重复赋予角色
                if(!authSet.contains(item)) {
                    DemoUserRole model = new DemoUserRole();
                    model.setUserId(param.getAuthId());
                    model.setRoleId(item);
                    model.setAddTime(LocalDateTime.now());
                    userRoleMapper.insertSelective(model);
                }
            });
        }
        // 删除被移除角色
        if(param.getDelItems() != null && param.getDelItems().size() > 0) {
            DemoUserRoleExample example = new DemoUserRoleExample();
            example.createCriteria().andUserIdEqualTo(param.getAuthId())
                    .andRoleIdIn(param.getDelItems());
            userRoleMapper.logicalDeleteByExample(example);
        }
        return ResponseUtil.ok();
    }

    /**
     * 获取当前已授角色id集合
     */
    private Set<Integer> existUserRoleSet(Integer authId) {
        List<DemoUserRole> list = queryUserRole(authId, null);
        Set<Integer> set = new HashSet<>();
        list.forEach(item -> {
            if(!set.contains(item.getRoleId())) {
                set.add(item.getRoleId());
            }
        });
        return set;
    }

    @Override//声明方法，实现方法
    public Object rolePermList(Integer roleId, Integer permId) {
        List<DemoRolePerm> models = queryRolePerm(roleId, permId);
        return ResponseUtil.ok(models);
    }

    /**
     * 查询角色-权限授权信息
     */
    private List<DemoRolePerm> queryRolePerm(Integer roleId, Integer permId) {
        DemoRolePermExample example = new DemoRolePermExample();
        DemoRolePermExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo((byte) 0);
        if(roleId != null) {
            criteria.andRoleIdEqualTo(roleId);
        }
        if(permId != null) {
            criteria.andPermIdEqualTo(permId);
        }
        return rolePermMapper.selectByExample(example);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)//给角色授权
    public Object batchAuthPerm(BatchAuthParam param) {
        if(!ArgumentUtil.notNull(param, param.getAuthId())) {
            return ResponseUtil.badArgument();
        }
        // 添加新角色

        if(param.getAddItems() != null && param.getAddItems().size() > 0) {
            //如果本身没有权限，是否无法通过这个if呢
            //其实这里不是数据库查看权限，是对于页面的权限勾选情况进行审查，如果勾选，则
            Set<Integer> authSet = existRolePermSet(param.getAuthId());
            //首先返回已经有的权限，这样之后添加的一定是非已有的权限
            param.getAddItems().forEach(item -> {
                if(!authSet.contains(item)) {
                    DemoRolePerm model = new DemoRolePerm();
                    model.setRoleId(param.getAuthId());
                    model.setPermId(item);
                    model.setAddTime(LocalDateTime.now());
                    rolePermMapper.insertSelective(model);
                }
            });
        }
        // 删除被移除角色
        if(param.getDelItems() != null && param.getDelItems().size() > 0) {
            DemoRolePermExample example = new DemoRolePermExample();
            example.createCriteria().andRoleIdEqualTo(param.getAuthId())//userid等于目前操作id
                    .andPermIdIn(param.getDelItems());//删除权限属于未删除的
            rolePermMapper.logicalDeleteByExample(example);
        }
        return ResponseUtil.ok();
    }

    /**
     * 获取当前已授权限id集合
     */
    private Set<Integer> existRolePermSet(Integer authId) {
        List<DemoRolePerm> list = queryRolePerm(authId, null);
        Set<Integer> set = new HashSet<>();
        list.forEach(item -> {
            if(!set.contains(item.getPermId())) {
                set.add(item.getPermId());
            }
        });
        return set;
    }

    @Override
    public Object rolePermVoList(Integer roleId, Integer permId) {
        List<DemoRolePerm> models = queryRolePerm(roleId, permId);//models与原始没区别
        return ResponseUtil.ok(rolePerm2vos(models));//但是这里的形参是VO处理过的models
    }

    /**
     * 权限引用
     */
    public Map<Integer, DemoPerm> refPerm(List<Integer> ids) {
        Map<Integer, DemoPerm> refMap = new HashMap<>();
        if(ids != null && ids.size() != 0) {
            DemoPermExample example = new DemoPermExample();
            example.setDistinct(true);
            example.createCriteria().andIdIn(ids);
            List<DemoPerm> models = permMapper.selectByExample(example);
            models.forEach(model -> refMap.put(model.getId(), model));
        }
        return refMap;
    }
    //基于vo
    private List<RolePermVo> rolePerm2vos(List<DemoRolePerm> models) {
        List<RolePermVo> vos = new LinkedList<>();
        List<Integer> roleIds = new LinkedList<>();
        List<Integer> permIds = new LinkedList<>();
        models.forEach(model -> {
            //每次循环，都是处理一个model，但是组装会需要这个model的参数来查找新的参数
            RolePermVo vo = new RolePermVo();
            // 拷贝model中与vo属性名相同值
            BeanUtils.copyProperties(model, vo);//方法类，首先拷贝
            vos.add(vo);
            if(!roleIds.contains(model.getRoleId())) {//这里看似多余，实则很关键，否则后面的map构建会很复杂
                //这里是构建不重复的Id list，便于后面直接构建
                roleIds.add(model.getRoleId());
            }
            if(!permIds.contains(model.getPermId())) {
                permIds.add(model.getPermId());
            }
        });
        // 补充vo中的引用值
        Map<Integer, DemoRole> refRole = refService.refRole(roleIds);//这里是建立id与name链接的位置
        Map<Integer, DemoPerm> refPerm = refPerm(permIds);
        vos.forEach(vo -> {//补充值
            if(refRole.get(vo.getRoleId()) != null) {//补充值
                vo.setRoleName(refRole.get(vo.getRoleId()).getName());
            }
            if(refPerm.get(vo.getPermId()) != null) {
                vo.setPermName(refPerm.get(vo.getPermId()).getName());
            }
        });
        return vos;
    }
}
